package nayasis.common.device.input;

import java.util.ArrayList;
import java.util.List;

import net.java.games.input.Controller;
import net.java.games.input.Controller.Type;
import net.java.games.input.ControllerEnvironment;

/**
 * 게임패드 이벤트 관리자
 */
public class GamePadEventManager {

	private static GamePadEventManager instance      = new GamePadEventManager();

	private List<GamePadEventHandler>  eventHandlers = new ArrayList<>();
	private List<Thread>               threadList    = new ArrayList<>();
	
	private boolean                    isStarted     = false;
	
	private GamePadEventManager() {}
	
	/**
	 * 게임패드 이벤트 관리자를 가져온다.
	 * 
	 * @return 게임패드 이벤트 관리자 Instance
	 */
	public static GamePadEventManager getInstance() {
		return instance;
	}

	/**
	 * 이벤트 처리기를 추가한다.
	 * 
	 * @param eventHandler 이벤트 처리기
	 */
	public void addEvent( GamePadEventHandler eventHandler ) {
		eventHandlers.add( eventHandler );
	}

	/**
	 * 이벤트 처리기를 삭제한다.
	 * 
	 * @param eventHandler 이벤트 처리기
	 */
	public void removeEvent( GamePadEventHandler eventHandler ) {
		eventHandlers.remove( eventHandler );
	}
	
	/**
	 * 게임패드 입력장치 감시를 시작한다.
	 */
	public void start() {
		
		if( isStarted == true ) return;
		
		isStarted = true;
		
		List<GamePadEvent> gamePadList = loadController();
		
		for( GamePadEvent gamePad : gamePadList ) {
			
			GamePadEventMonitorThread eventSource = new GamePadEventMonitorThread( gamePad );
			
			eventSource.addObserver( new GamePadEventObserver(eventHandlers) );
			
			Thread thread = new Thread( eventSource );
			
			threadList.add( thread );
		
			thread.start();
			
		}
		
	}

	/**
	 * 게임패드 입력장치 감시를 중지한다.
	 */
	public void stop() {
		
		if( ! isStarted ) return;
		
		for( Thread thread : threadList ) {
			thread.interrupt();
		}
		
		isStarted = false;
		
	}
	
	/**
	 * OS 자원을 검색해 입력장치 중 게임패드를 검색한다.
	 * 
	 * @return 게임패드 목록
	 */
	private List<GamePadEvent> loadController() {

		List<GamePadEvent> result = new ArrayList<>();
		
		ControllerEnvironment ce = ControllerEnvironment.getDefaultEnvironment();
		
		Controller[] list = ce.getControllers();
		
		int index = 0;

		for( Controller controller : list ) {
			
			if( isGamePad(controller) ) {
				
				result.add( new GamePadEvent( index++, controller ) );
				
			}
			
		}
		
		return result;

	}
	
	/**
	 * Controller 가 게임패드인지 여부를 확인한다.
	 * 
	 * @param controller 입력장치
	 * @return 게임패드 여부
	 */
	private boolean isGamePad( Controller controller ) {
		
		Type type = controller.getType();
		
		return type == Controller.Type.STICK || type == Controller.Type.GAMEPAD;

	}
	
}
